package Subject;

use FileHandle;
use Moose;
use Data::Dumper;
use Set::Scalar;

use Const;
use SubjectConfig;
use Log;
use IFile;

has 'id' => (
    is => 'rw',
    isa => 'Str',
    required => 1,
    );


has 'filename' => (
    is => 'rw' ,
    isa => 'Str',
    );

has 'ifile' => (
    is => 'rw',
    isa => 'IFile',
    );

has 'model' => (
    is => 'rw',
    isa => 'Model',
    );

has 'subject' => (
    is => 'ro',
    isa => 'Str',
    );

has 'nominal_section' => (
    is => 'rw',
    isa => 'HashRef',
    default => { sub { return { }; } },
    init_arg => undef,
    );

has 'assertion_section' => (
    is => 'rw',
    isa => 'HashRef',
    default => { sub { return { }; } },
    init_arg => undef,
    );

has 'model_sections_names' => (
    is => 'rw',
    isa => 'ArrayRef[SectionName]',
    init_arg => undef,
    );

has 'reserved_sections_names' => (
    is => 'rw',
    isa => 'ArrayRef[SectionName]',
    init_arg => undef,
    );

has '_assertion_parser_state' => (
    is => 'rw',
    isa => 'Int',
    init_arg => undef,
    );

has 'config' => (
    is => 'rw',
    isa => 'SubjectConfig',
    default => { sub { return SubjectConfig->new(); }  },
    init_arg => undef,
    );

sub BUILD {
    my $self = shift;
    $self->load();
}

sub computeFileName {
    my $self = shift;
    my $f = $self->model->root."/".$self->id;
    if ( -d $f ) {
	$f.="/".Const::SUBJECT_DATA_FILE_IF_DIR;	
    }
    if ( ! -f $f ) {
	my $l=Log->instance;
	$l->xsupererror("01fbc331-1400-3685-a0e2-341b3c093876",
			$l->format($self->id,'',"is not a regular file or directory does not contain data file: $f")); 	
    }
    if ( ! -r $f ) {
	my $l=Log->instance;
	$l->xsupererror("152c73ff-36f5-3ad8-97f2-be12dca0a974",
			$l->format($self->id,'',"does not represent a readable file: $f")); 
    }
    return $f;
}

sub createNewChild {
    my $self = shift;

}

sub _createNewChild_DefaultConfig {
     my $self = shift;
     my $conf = SubjectConfig->new();
     
}

sub load {
    my $self = shift;
    $self->ifile(IFile->new(filename => $self->computeFileName));
    my $iter = $self->ifile->iter;
    my 	$current_section_name = undef; 

    # 's'   : start status
    # 'cs'  : configuration mode
    # 'ns'  : nominal section mode
    # 'ss'  : semantic section mode
    # 'e'   : end status
    my $status = 's';
    my $is_header = 0;

    while ( $iter->has_next ) {
        my $next = $iter->next;
#        print $next->{'key'}   . "\n";
#        print $next->{'value'} . "\n";

	my $re = "^=+|\s+(".Const::SECTION_NAME_RE.")\s+|=+";
	$is_header = ($next->value =~ /$re/o);
	if($is_header) {
	    $current_section_name = SectionName->new(name => $1);	    
	}else{
	    
	}
	
	# main finite state machine:
	if($status eq 's') {
	    if($is_header) {
		if($current_section_name->name eq Const::SECTION_NAME_CONFIG) {
		    $status = 'cs';
		}else{
		    # sintax: config expected
		}
	    }elsif(! $next->isEmpty) {
		# sintax error: data out of section
	    }
	}elsif($status eq 'cs') {	    
	    if($is_header) {
		if($current_section_name->type eq 'sectionNominal') {
		    if(exists($self->nominal_sections->{$current_section_name->name})) {
			# error: already exists
		    }else{
			$self->nominal_sections->{$current_section_name->name} = '';
			$status = 'ns';
		    }
		}elsif($current_section_name->type eq 'sectionReserved') {		    
		    $self->_createReservedSection($current_section_name->name);
		    $status = 'ss';
		}
	    }else {
		# add any line value to the content:
		$self->_readConfigLine($next->value);
	    }
	}elsif($status eq 'ns') {
	    if($is_header) {
		if($current_section_name->type eq 'sectionNominal') {
		    if(exists($self->nominal_sections->{$current_section_name->name})) {
			# error: already exists
		    }else{
			$self->nominal_sections->{$current_section_name->name} = '';
			# same status
		    }
		}elsif($current_section_name->type eq 'sectionReserved') {
		    if(exists($self->nominal_sections->{$current_section_name->name})) {
			# error: already exists
		    }else{
			$self->_createReservedSection($current_section_name->name);
			$status = 'ss';
		    }
		}else{
		    # internal
		}
	    }else {
		# add any line value to the content:
		$self->nominal_sections->{$current_section_name->name} .= $next->raw_value;
	    }
	}elsif($status eq 'ss') {
	    if($is_header) {
		if($current_section_name->type eq 'sectionNominal') {
		    # error: semantic section after nominal section 
		}elsif($current_section_name->type eq 'sectionReserved') {
		    if(exists($self->nominal_sections->{$current_section_name->name})) {
			# error: already exists
		    }else{
			$self->_createReservedSection($current_section_name->name);
		    }
		}else{
		    # internal
		}
	    }else {
		$self->_processReservedILine($current_section_name->name,$next);
	    }
	}else{
	    # internal
	}	
    }
}

sub _createReservedSection {
    my $s=shift;
    my $name=shift;
    if($name eq Const::SECTION_NAME_ASS_THIS ||
       $name eq Cosnt::SECTION_NAME_ASS_CHILDREN
       $name eq Cosnt::SECTION_NAME_ASS_ALL)
    {	
	$s->_createAssertionSection($name);
    }else{
	# error, unkown reserved section
    }
}

sub _processReservedILine {
   my $s=shift;
   my $name=shift;
   my $iline =shift;
    if($name eq Const::SECTION_NAME_ASS_THIS ||
       $name eq Cosnt::SECTION_NAME_ASS_CHILDREN
       $name eq Cosnt::SECTION_NAME_ASS_ALL)
    {
	$s->_processAssertionSection($name,$iline);
    }else{
	# error, unkown reserved section
    }
}

sub _createAssertionSection {
    my $s=shift;
    my $name=shift;
    if(exists($s->assertion_sections->{$name})) {
	# error
    }else{
	$s->assertion_section->{$name} = { };
	$s->_assertion_parser_state(0);
    }
}

sub _processAssertionSection {
    my $s=shift;
    my $name=shift;
    my $iline=shift;
    if($s->_assertion_parser_state == 0 ) {
	if($iline->indent == 0 && $iline->what eq 'data') {
	    TBD ddddd
	}
    }else{
	
    }
}

sub _readConfigLine {
    my $self = shift;
    my $line = shift;
    my $txt = $line->value;
    $txt =~ /^(\w+)\s*=\s*(.*)$/o;
    my ($k,$v) = ($1,$2);
    if(! $self->config->set_soft($k,$v)) { 
	# error
    }
	
}

sub getNominalSectionNames {
    my $self = shift;
    return $self->model_sections_names;
}

sub getReservedSectionNames {
    my $self = shift;
    return $self->reserved_sections_names;
}

sub getSection {
    my $self = shift;
    my $section = shift;
    my $d = $self->sections;
    if(!exists($d->{$section})) {
	my $l=Log->instance;
	$l->xsuperserror("2efd1396-4f01-34b1-98f3-0378070a709f",
			 $l->format($self->id,'$section',"section does not exist")); 
    }
    return $d->{$section};
}

sub save {
    
}


no Moose;
__PACKAGE__->meta->make_immutable;
